#include "AlgoEvaluatorModule1EnvirNoise.h"
#include <cmath> // For pow, log10

class algo::AlgoEvaluatorModule1EnvirNoisePrivate 
{
public:

};

algo::AlgoEvaluatorModule1EnvirNoise::AlgoEvaluatorModule1EnvirNoise()
	: d(new AlgoEvaluatorModule1EnvirNoisePrivate)
{
}

algo::AlgoEvaluatorModule1EnvirNoise::~AlgoEvaluatorModule1EnvirNoise()
{
	delete d;
}

std::vector<algobase::EvaluateEnvirDataType> algo::AlgoEvaluatorModule1EnvirNoise::getNeedType()
{
	return std::vector<algobase::EvaluateEnvirDataType>({ algobase::EEDT_Rain, algobase::EEDT_Wind, algobase::EEDT_ShipNoise });
}

int algo::AlgoEvaluatorModule1EnvirNoise::exec(
	const algobase::Path& path,
	double& result,
	algobase::EvaluateModuleCoords& resultCoords)
{
	if (path.empty())
	{
		result = 0.0; // Assuming 0 dB for no path, or could be a specific low value.
		resultCoords.clear();
		return 0;
	}

	auto db = getDB();
	if (!db) {
		return -1;
	}

	double total_linear_noise = 0.0;
	resultCoords.resize(path.size());

	for (size_t i = 0; i < path.size(); ++i)
	{
		resultCoords[i].Assign(path[i]);

		// Get noise data in dB for each source
		double rain_noise_db = db->getData(algobase::EEDT_Rain, getTaskConfig().mStartTime, path[i].mCoordZ, 0.0f);
		double wind_noise_db = db->getData(algobase::EEDT_Wind, getTaskConfig().mStartTime, path[i].mCoordZ, 0.0f);
		double ship_noise_db = db->getData(algobase::EEDT_ShipNoise, getTaskConfig().mStartTime, path[i].mCoordZ, 0.0f);

		// Convert dB to linear scale (proportional to intensity)
		double rain_linear = std::pow(10.0, rain_noise_db / 10.0);
		double wind_linear = std::pow(10.0, wind_noise_db / 10.0);
		double ship_linear = std::pow(10.0, ship_noise_db / 10.0);

		// Sum the linear values to get total noise intensity at the point
		double point_total_linear = rain_linear + wind_linear + ship_linear;
		total_linear_noise += point_total_linear;

		// Store the total noise in dB for this specific point for debugging/analysis
		if (point_total_linear > 0) {
			resultCoords[i].mRawValue = 10.0 * std::log10(point_total_linear); // Store raw value as well
		} else {
			resultCoords[i].mRawValue = 0.0; // Store raw value as well
		}

		resultCoords[i].mResult = calcScore(resultCoords[i].mRawValue);
	}

	// Calculate the average linear noise over the path
	double avg_linear_noise = total_linear_noise / path.size();

	// Convert the average linear noise back to dB to get the final raw value
	if (avg_linear_noise > 0) {
		result = calcScore(10.0 * std::log10(avg_linear_noise));
	} else {
		result = calcScore(0.0); // Or a very low dB value representing silence
	}

	return 0;
}

double algo::AlgoEvaluatorModule1EnvirNoise::calcScore(double rawValue) const
{
	return benefitSigmoid(rawValue, 95.0, 5.0) * getWeight();
}

double algo::AlgoEvaluatorModule1EnvirNoise::calcRaw(const std::vector<double>& rawValues) const
{
	double total_value = 0;
	for (const auto& val : rawValues) {
		total_value += val;
	}
	return total_value / rawValues.size();
}
